package com.whl215.customview.jk

import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.text.TextPaint
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import androidx.core.content.ContextCompat
import com.whl215.customview.R


/**
 * 数字改变时 滑动切换文本
 */
class ScrollNumberView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val mNormalPaint: TextPaint by lazy { TextPaint() }
    private val mTextOriginalPaint: TextPaint by lazy { TextPaint() }
    private val mTextNowPaint: TextPaint by lazy { TextPaint() }
    private var mInY: Float = 0f
    private var mOutY: Float = 0f
    private var mInAlpha = 0
    private var mOutAlpha = 0
    private var mBaselineY = 0

    var number: Int = 0

    /**
     * true 增加 +1
     * false 减少 -1
     */
    var added: Boolean = false
        set(value) {
            field = value
            originalNumber = number
            nowNumber = if (added) number.plus(1) else number.minus(1)
            number = nowNumber
            startAnimAlpha()
            startAnimTranY()
        }

    private var originalNumber = 0
    private var nowNumber = 0
    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScrollNumberView)
        val textColor = typedArray.getColor(
            R.styleable.ScrollNumberView_smTextColor,
            ContextCompat.getColor(context, android.R.color.darker_gray)
        )
        val textSize = typedArray.getDimension(
            R.styleable.ScrollNumberView_smTextSize,
            TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP,
                12f,
                context.resources.displayMetrics
            )
        )
        mTextOriginalPaint.isAntiAlias = true
        mTextOriginalPaint.color = textColor
        mTextOriginalPaint.textSize = textSize
        mTextNowPaint.isAntiAlias = true
        mTextNowPaint.color = textColor
        mTextNowPaint.textSize = textSize
        mNormalPaint.isAntiAlias = true
        mNormalPaint.color = textColor
        mNormalPaint.textSize = textSize
        typedArray.recycle()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val fm = mTextOriginalPaint.fontMetrics
        val height = fm.bottom - fm.top
        mBaselineY =
            (height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent).toInt()
        //存在进位的可能 所以乘10 使用进位后的数值测量宽度
        val width = mNormalPaint.measureText(number.times(10).toString())
        setMeasuredDimension(width.toInt(), height.toInt())
    }

    override fun onDraw(canvas: Canvas?) {
        canvas?.let {
            changeText(it, mBaselineY.toFloat())
        }
    }


    private fun changeText(canvas: Canvas, baseLineY: Float) {
        val nowNumberText = if (nowNumber==0) " " else nowNumber.toString()
        val originalNumberText = if (originalNumber==0) " " else   originalNumber.toString()
        var textWidth = 0f
        for (i in nowNumberText.indices) {
            val nowStr = nowNumberText[i]
            val originalStr = originalNumberText[i]
            if (nowStr == originalStr) {
                canvas.drawText(originalStr.toString(), textWidth, baseLineY, mNormalPaint)
                textWidth = textWidth.plus(mNormalPaint.measureText(originalStr.toString()))
            } else {
                mTextOriginalPaint.alpha = mInAlpha
                mTextNowPaint.alpha = mOutAlpha
                canvas.drawText(
                    originalNumberText.substring(i, originalNumberText.length),
                    textWidth,
                    mInY,
                    mTextOriginalPaint
                )
                canvas.drawText(
                    nowNumberText.substring(i, nowNumberText.length),
                    textWidth,
                    mOutY,
                    mTextNowPaint
                )
                break
            }
        }
    }



    private val mAnimInAlpha: ValueAnimator by lazy {
        val duration = 500L
        val start = 255
        val end = 0
        val animator =
            ObjectAnimator
                .ofInt(start, end)
                .setDuration(duration)
        animator.addUpdateListener {
            mInAlpha = it.animatedValue.toString().toInt()
            invalidate()
        }
        return@lazy animator
    }
    private val mAnimOutAlpha: ValueAnimator by lazy {
        val duration = 500L
        val start = 0
        val end = 255
        val animator =
            ObjectAnimator
                .ofInt(start, end)
                .setDuration(duration)
        animator.addUpdateListener {
            mOutAlpha = it.animatedValue.toString().toInt()
            invalidate()
        }
        return@lazy animator

    }
    private val mAnimInYChecked: ValueAnimator by lazy {
        val duration = 500L
        val start: Int = mBaselineY
        val end: Int = mBaselineY - height
        val animator =
            ObjectAnimator
                .ofInt(start, end)
                .setDuration(duration)
        animator.addUpdateListener {
            mInY = it.animatedValue.toString().toFloat()
            invalidate()
        }
        return@lazy animator
    }
    private val mAnimInYUnChecked: ValueAnimator by lazy {
        val duration = 500L
        val start: Int = mBaselineY
        val end: Int = mBaselineY + height
        val animator =
            ObjectAnimator
                .ofInt(start, end)
                .setDuration(duration)
        animator.addUpdateListener {
            mInY = it.animatedValue.toString().toFloat()
            invalidate()
        }
        return@lazy animator
    }
    private val mAnimOutYChecked: ValueAnimator by lazy {
        val duration = 500L
        val start: Int = mBaselineY + height
        val end: Int = mBaselineY
        val animator =
            ObjectAnimator
                .ofInt(start, end)
                .setDuration(duration)
        animator.addUpdateListener {
            mOutY = it.animatedValue.toString().toFloat()
            invalidate()
        }
        return@lazy animator
    }
    private val mAnimOutYUnChecked: ValueAnimator by lazy {
        val duration = 500L
        val start: Int = mBaselineY - height
        val end: Int = mBaselineY
        val animator =
            ObjectAnimator
                .ofInt(start, end)
                .setDuration(duration)
        animator.addUpdateListener {
            mOutY = it.animatedValue.toString().toFloat()
            invalidate()
        }
        return@lazy animator
    }

    private fun startAnimAlpha() {
        mAnimInAlpha.start()
        mAnimOutAlpha.start()
    }

    private fun startAnimTranY() {
        if (added){
            mAnimInYChecked.start()
            mAnimOutYChecked.start()
        }else{
            mAnimInYUnChecked.start()
            mAnimOutYUnChecked.start()
        }

    }

    override fun onDetachedFromWindow() {
        if (mAnimInAlpha.isRunning)mAnimInAlpha.cancel()
        if (mAnimInYChecked.isRunning)mAnimInYChecked.cancel()
        if (mAnimOutYChecked.isRunning)mAnimOutYChecked.cancel()
        if (mAnimInYUnChecked.isRunning)mAnimInYUnChecked.cancel()
        if (mAnimOutYUnChecked.isRunning)mAnimOutYUnChecked.cancel()
        super.onDetachedFromWindow()
    }


}